import cv2
import numpy as np


class Filter:
    def __init__(self, padding, type):
        self.padding = padding
        self.type = type

    def __call__(self, src, size, sigma=None):
        
        h, w = src.shape

        m = (size - 1) // 2

        dst = np.zeros_like(src).tolist()

        src = self.padding(src, size)

        if self.type == 'MEAN':
            self.kernel = np.ones((size, size), dtype='float32') / (size * size)
        elif self.type == 'GAUSS':
            ix = np.abs(np.arange(-m, m + 1))
            iy = abs(ix.reshape((-1, 1)))
            self.kernel = np.exp(-(ix * ix + iy * iy) / (2 * sigma ** 2))
            wi = np.sum(self.kernel)
            self.kernel /= wi

        for y in range(0, h):
            for x in range(0, w):
                dst[y][x] = np.sum(self.kernel * src[y: y + 2 * m + 1, x: x + 2 * m + 1])
        
        dst = np.array(dst).astype('uint8')

        return dst
    
    def get_kernel(self):
        return self.kernel


if __name__ == '__main__':
    from padding import Padding

    SRC = cv2.imread('lena.bmp', cv2.IMREAD_GRAYSCALE)

    def show(winname, img):
        cv2.imshow(winname, img)
        cv2.resizeWindow(winname, 512, 512)
        cv2.waitKey(1)

    show('MEAN', Filter(Padding('REPEAT'), 'MEAN')(SRC, 3))

    show('GAUSS', Filter(Padding('REPEAT'), 'GAUSS')(SRC, 19, 2))

    cv2.waitKey(0)